#ifndef XLCOMM_BASE_BLOCKINGQUEUE_H_
#define XLCOMM_BASE_BLOCKINGQUEUE_H_

#include <condition_variable>
#include <deque>
#include <mutex>

#include "xlcomm/define.h"
#include "xlcomm/noncopyable.h"

namespace xlcomm {

// 线程安全的阻塞队列（先排队、慢处理）
template <typename T>
class BlockingQueue : noncopyable {
 public:
  using QueueType = std::deque<T>;

  BlockingQueue() {}

  // 存放一个数据到队列里。完成后如果有线程等待取数据，则唤醒一个
  void Put(const T& x) {
    std::lock_guard<std::mutex> lock(mutex_);
    queue_.push_back(x);
    condition_.notify_one();
  }

  // 移动一个数据到队列里。完成后如果有线程等待取数据，则唤醒一个
  void Put(T&& x) {
    std::lock_guard<std::mutex> lock(mutex_);
    queue_.push_back(std::move(x));
    condition_.notify_one();
  }

  // 从队列里取出一个数据。如果队列为空，则阻塞等待
  T Take() {
    std::unique_lock<std::mutex> lock(mutex_);
    while (queue_.empty()) {
      condition_.wait(lock);
    }
    T x = std::move(queue_.front());
    queue_.pop_front();
    return x;
  }

  // 获取队列的大小
  size_t Size() const {
    std::lock_guard<std::mutex> lock(mutex_);
    return queue_.size();
  }

  // 把队列转移出来
  QueueType Drain() {
    QueueType queue;
    {
      std::lock_guard<std::mutex> lock(mutex_);
      queue = std::move(queue_);
    }
    return queue;
  }

 private:
  mutable std::mutex mutex_;
  std::condition_variable condition_;
  QueueType queue_;
};

}  // namespace xlcomm

#endif  // XLCOMM_BASE_BLOCKINGQUEUE_H_